package org.tony.spider.novel.utils;

import java.util.Iterator;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.VisitorSupport;
import org.tony.common.xml.XmlHelper;
import org.tony.spider.novel.common.BooksContext;
import org.tony.spider.novel.common.SitesContext;
import org.tony.spider.novel.entries.Book;
import org.tony.spider.novel.entries.BookStatus;

public class BookConfigUtil
{
  private static BookConfigUtil instance;
  private static final String   PATH = "novel/books.xml";

  private BookConfigUtil()
  {
    this.read();
  }

  public synchronized void read()
  {
    Document doc = XmlHelper.read(PATH);
    if (doc != null)
    {
      doc.accept(new VisitorSupport() {
        public void visit(Element node)
        {
          if (!node.isRootElement() && node.getName().equals("book"))
          {
            String id = node.attributeValue("id");
            String name = node.attributeValue("name");
            String status = node.attributeValue("status");
            String lastUpdated = node.attributeValue("last-update");
            String fromSite = node.attributeValue("from-site");
            String url = node.attributeValue("url");

            Book book = new Book();
            book.setId(id);
            book.setName(name);
            book.setStatus(BookStatus.valueOf(status));
            book.setLastUpdated(lastUpdated);
            book.setFromSite(SitesContext.getInstance().get(fromSite));
            book.setUrl(url);
            BooksContext.getInstance().put(id, book);
          }
        }
      });
    }
  }

  public synchronized void write(Book book)
  {
    Document doc = XmlHelper.read(PATH);
    if (doc != null)
    {
      Element root = doc.getRootElement();
      Element bookEle = root.addElement("book");
      bookEle.addAttribute("id", book.getId());
      bookEle.addAttribute("name", book.getName());
      bookEle.addAttribute("status", book.getStatus().name());
      bookEle.addAttribute("last-update", book.getLastUpdated());
      bookEle.addAttribute("from-site", book.getFromSite().getSiteName());
      bookEle.addAttribute("url", book.getUrl());
      XmlHelper.write(PATH, doc);
      BooksContext.getInstance().put(book.getId(), book);
    }
  }

  public synchronized void update(Book book)
  {
    Document doc = XmlHelper.read(PATH);
    if (doc != null)
    {
      Element el = (Element)doc.selectSingleNode(String.format("//books/book[@id=%s]", book.getId()));
      if (el != null)
      {
        el.attribute("id").setValue(book.getId());
        el.attribute("name").setValue(book.getName());
        el.attribute("status").setValue(book.getStatus().name());
        el.attribute("last-update").setValue(book.getLastUpdated());
        el.attribute("from-site").setValue(book.getFromSite().getSiteName());
        el.attribute("url").setValue(book.getUrl());
        XmlHelper.write(PATH, doc);
        BooksContext.getInstance().put(book.getId(), book);
      }
      else
      {
        write(book);
      }
    }
  }

  public synchronized void update(String id, Map<String, String> properties)
  {
    Document doc = XmlHelper.read(PATH);
    if (doc != null)
    {
      Element el = (Element)doc.selectSingleNode(String.format("//books/book[@id=%s]", id));
      if (el != null)
      {
        for (Iterator<String> keyIter = properties.keySet().iterator(); keyIter.hasNext();)
        {
          String key = keyIter.next();
          el.attribute(key).setValue(properties.get(key));
        }
      }
      XmlHelper.write(PATH, doc);
    }
  }

  public synchronized void remove(Map<String, String> condition)
  {
    StringBuilder xpath = new StringBuilder("//books/book");
    Document doc = XmlHelper.read(PATH);
    if (doc != null)
    {
      boolean first = true;
      for (Iterator<String> keyIter = condition.keySet().iterator(); keyIter.hasNext();)
      {
        String key = keyIter.next();
        if (first)
        {
          xpath.append("[");
          first = false;
        }
        xpath.append(String.format("@%s='%s'", key, condition.get(key)));
        if (keyIter.hasNext())
        {
          xpath.append(" and ");
        }
        else
        {
          xpath.append("]");
        }
      }
      System.out.println(xpath);
      Element el = (Element)doc.selectSingleNode(xpath.toString());
      if (el != null)
      {
        el.getParent().remove(el);
        XmlHelper.write(PATH, doc);
        BooksContext.getInstance().remove(condition.get("id"));
      }
    }
  }

  public static final synchronized BookConfigUtil getInstance()
  {
    if (instance == null)
    {
      instance = new BookConfigUtil();
    }
    return instance;
  }
}
